<html>

<head>
    <script src="https://unpkg.com/@tensorflow/tfjs"></script>
</head>
<script>
    // 虹膜分类器
    async function run() {
        // 鸢尾花.csv文件中有四个特征值，一个标签值， 第一行顶部有列名。
        let csvUrl = 'http://127.0.0.1:8080/tensorflow-js-1/static/index_1/iris.csv'
        // 实例化tf.data.csv时，参数1：csv的地址 参数2：配置
        const trainingData = tf.data.csv(csvUrl, {
            // 还指定物种列是一个标签   species标签的一列
            // 指定后，tensorflow.js 将识别出 “物种(species)” 列是一个标签 ，它将是 y 集合的一部分。 其他一切都将是功能 
            columnConfigs: {
                species: {
                    isLabel: true
                }
            }
        })
        // 设置几个变量。 
        // 一个是特征的数量，特征的数量是列名。length 减去一因为我知道我只有一个标签   iris.csv中实际上有 150 个样本，减去了第一行的标题
        const numOfFeatures = (await trainingData.columnNames()).length - 1;
        const numOfSamples = 150;
        // 将来自 tf.data.csv 的数据 转换为数组
        console.log(trainingData);
        const convertedData = trainingData.map(({ xs, ys }) => {
            // 创建我的 labels 数组 ，里面有三个元素
            const labels = [
                ys.species == "setosa" ? 1 : 0,
                ys.species == "virginica" ? 1 : 0,
                ys.species == "versicolor" ? 1 : 0,
            ]
            return { xs: Object.values(xs), ys: Object.values(labels) };
        }).batch(10);
        // batch(10) 把它们分成一批 10 个

        // 创建一个模型，将模型定义为 tf.sequential
        const model = tf.sequential();
        // 添加带有五个神经元的隐藏层  
        // 这五个单元 由 sigmoid 函数激活
        model.add(tf.layers.dense({
            inputShape: [numOfFeatures],
            activation: "sigmoid",
            units: 5
        }))
        // 加三个神经元，用 Softmax 函数激活它们
        // 我的输出层里面会有 三个单元  因为我只有三个类别
        // 它会被 softmax 激活，因为我想 尝试 尽可能多地模拟热编码，其中一个神经元会 为即将出现的实际类亮起，
        model.add(tf.layers.dense({ activation: "softmax", units: 3 }))
        // 编译模型 具有分类交叉熵损失的模型和学习率为 0.06 的 AdamOptimizer
        model.compile({
            loss: "categoricalCrossentropy",
            optimizer: tf.train.adam(0.06)
        })
        // 进行训练
        await model.fitDataset(convertedData, {
            // 训练100个迭代
            epochs: 100,
            // 回调函数
            callbacks: {
                // 每一个迭代输出训练结果
                onEpochEnd: async (epoch, logs) => {
                    console.log("Epoch:" + epoch + ' Loss:' + logs.loss);
                }
            }
        })
        // 创建一个包含 特征值的输入张量 并将其传递给模型的预测方法
        // 声明为张量 2D
        // 其中有 四个值分别是花瓣和萼片的长度和宽度， 然后是该张量的形状。
        const testVal = tf.tensor2d([6.2, 2.1, 4.3, 1.3], [1, 4]);
        // 传递给预测方法，然后我们会得到一个里面有预测的 Tensor
        const prediction = model.predict(testVal);
        alert(prediction)
    }
    run();
</script>

</html>